import type { Nullable } from "../common";

/**
 * #### 对象类型的所有键转联合类型
 * @category Object
 * @example
 * ```ts
 * type A = { a: 1; b: 2; c: 3 };
 * type B = KeysToUnion<A>; // 'a' | 'b' | 'c'
 * ```
 */
export type KeysToUnion<T> = keyof T;

/**
 * #### 获取对象类型的值构成的联合类型
 * @category Object
 * @example
 * ```ts
 * type A = { a: 1; b: 2; c: 3 };
 * type B = Values<A>; // 1 | 2 | 3
 * ```
 */
export type Values<T> = T[KeysToUnion<T>];

/**
 * #### 获取对象类型键够成的元组类型
 * @category Object
 * @example
 * ```ts
 * type A = { a: 1; b: 2; c: 3 };
 * type B = KeysToTuple<A>; // ['a', 'b', 'c']
 */
export type KeysToTuple<T> = KeysToTuple<T>[];

/**
 * #### 提取出符合类型 V 的属性
 * @category Object
 * @example
 * ```ts
 * type A = { a: 1; b: 2; c: 3 };
 * type B = ExtractKeys<A, 1>; // {a:1}
 * ```
 */
export type ExtractValues<T, V> = {
  [Key in keyof T as T[Key] extends V ? Key : never]: T[Key];
};

/**
 * #### 过滤出不符合类型 V 的属性
 * @category Object
 * @example
 * ```ts
 * type A = { a: 1; b: 2; c: 3 };
 * type B = ExcludeValues<A, 1>; // { b: 2; c: 3 }
 * ```
 */
export type ExcludeValues<T, V> = {
  [Key in keyof T as T[Key] extends V ? never : Key]: T[Key];
};

/**
 * #### 提取出符合类型 U 的键名构造新的对象类型
 * @category Object
 * @example
 * ```ts
 * type A = { a: 1; b: 2; c: 3 };
 * type B = ExtractValues<A, 'a'>; // { a: 1 }
 * ```
 */
export type Include<T extends object, U extends keyof any> = {
  [Key in keyof T as Key extends U ? Key : never]: T[Key];
};

/**
 * #### 只读对象
 * @category Object
 *  @example
 * ```ts
 * type A = { a: 1; b: 2; c: 3 };
 * type B = Readonly<A>; // { readonly a: 1; readonly b: 2; readonly c: 3 }
 * ```
 */
export type RaedonlyPartial<T> = {
  readonly [Key in keyof T]?: T[Key];
};

/**
 * #### 将对象类型的所有属性转为可选
 */
export type PartialOptional<T, K extends keyof T> = {
  [P in K]?: T[P];
};

/**
 * #### 将对象类型的所有属性转为可选
 * @category Object
 * @example
 * ```ts
 * type A = { a: 1; b: 2; c: 3 };
 * type B = DeepPartial<A>; // { a?: 1; b?: 2; c?: 3 }
 * ```
 */
export type DeepPartial<T> = {
  [Key in keyof T]?: T[Key] extends object ? DeepPartial<T[Key]> : T[Key];
};

/**
 * #### 将对象类型的每个属性值转为 get 和 set 形式
 * @category Object
 * @example
 * ```ts
 * type A = { a: 1; b: 2; c: 3 };
 * type B = Proxify<A>; // { get a(): 1; set a(value: 1): void; get b(): 2; set b(value: 2): void; get c(): 3; set c(value: 3): void; }
 * ```
 */
export type Proxify<T> = {
  [P in keyof T]: {
    get(): T[P];
    set(value: T[P]): void;
  };
};

/**
 * ####  向对象类型中添加 get 和 set 前缀
 * @category Object
 * @example
 * ```ts
 * type A = { a: 1; b: 2; c: 3 };
 * type B = GetterSetterPrefix<A>; // { getA(): 1; setA(value: 1): void; getB(): 2; setB(value: 2): void; getC(): 3; setC(value: 3): void; }
 * ```
 */
export type GetterSetterPrefix<T> = {
  [Key in keyof T as Key extends string ? `get${Capitalize<Key>}` : never]: {
    (): T[Key];
  };
} & {
  [Key in keyof T as Key extends string ? `set${Capitalize<Key>}` : never]: {
    (value: T[Key]): void;
  };
};

/**
 * #### 将对象类型中的每个属性值转为可空类型
 * @category Object
 * @example
 * ```ts
 * type A = { a: 1; b: 2; c: 3 };
 * type B = NullableValue<A>; // { a?: 1; b?: 2; c?: 3 }
 * ```
 */
export type NullableValue<T> = {
  [Key in keyof T]: Nullable<T[Key]>;
};

/**
 * #### 将对象类型的属性值填充为类型 T
 * @category Object
 * @example
 * ```ts
 * type A = { a: 1; b: 2; c: 3 };
 * type B = ChangeRecordType<A, string>; // { a: string; b: string; c: string; }
 * ```
 */
export type ChangeRecordType<K, T = undefined> = {
  [P in keyof K]?: T;
};

/**
 * #### 将对象类型的属性值变为可写
 * @category Object
 * @example
 * ```ts
 * type A = { readonly a: 1; readonly b: 2; readonly c: 3 };
 * type B = Mutable<A>; // { a: 1; b: 2; c: 3 }
 * ```
 */
export type Mutable<T> = {
  -readonly [P in keyof T]: T[P];
};

// type A = { a: 1; b: 2; c: 3 };
// type B = KeysToUnion<A>;
// type D = KeysToTuple<A>;
// type E = ExtractValues<A, 1>;
// type F = DeepPartial<A>;
// type G = ChangeRecordType<A>;
// type C = Values<A>;

// 定义一个类型，用于获取两个对象类型的交集
export type Intersection<T extends object, U extends object> = Pick<
  T,
  Extract<keyof T, keyof U> & Extract<keyof U, keyof T>
>;

// 定义一个类型，用于获取两个对象类型的差集
export type Diff<T extends object, U extends object> = Pick<
  T,
  Exclude<keyof T, keyof U>
>;

// 定义一个类型，表示集合A和B的差集
type SetDifference<A, B> = Exclude<A | B, A & B>;
// 定义一个类型，表示集合A和B的对称差集，即A和B的差集和A和B的交集的差集
export type SymmetricDifference<A, B> = SetDifference<A | B, A & B>;

// 定义一个类型，用于覆盖两个对象类型的属性
export type Overwrite<
  T extends object,
  U extends object,
  I = Diff<T, U> & Intersection<U, T>
> = Pick<I, keyof I>;

// 导出一个类型，用于将两个对象的属性合并
export type Assign<
  // 第一个对象类型
  T extends object,
  // 第二个对象类型
  U extends object,
  // 合并后的对象类型，默认为第一个对象类型与第二个对象类型的差集与第二个对象类型的交集
  I = Diff<T, U> & U
> = Pick<I, keyof I>;

// 定义一个类型，将联合类型转换为交叉类型
export type UnionToIntersection<U> =
  // 如果U是任意类型，则返回一个函数，该函数接受一个参数k，参数类型为U
  (U extends any ? (k: U) => void : never) extends (arg: infer U) => void
    ? // 如果上述表达式可以推断出U类型，则返回U类型
      U
    : // 否则返回never类型
      never;
